Code to process Parekh paper data

This code is assembled to perform the steps to summarize differentially expressed genes and clusters of cells. The processed data were downloaded and saved in SEUSS_processed_data.

This cade has been pulled from https://github.com/yanwu2014/SEUSS-Analysis and specifically copied from hESC_summarize_results.R

The data for cells cultured in the pluripotent stem cell medium has been put into a compressed file in the Google Drive. You should be able to download it from the following link: https://drive.google.com/open?id=19qHsRFO4QwHhotxuw73MYRHB8CFYPM3c and extract the files onto your local computer. You will also need to change the file.handle appropriately (see below).

NOTE

The following packages must be installed prior to running (many needed only to load swne package. Uncomment to execute.

getPackageIfNeeded <- function(pkg) {
  if (!require(pkg, character.only=TRUE, quietly =TRUE))
    install.packages(pkgs=pkg, dependencies=TRUE)
}
getBiocPackageIfNeeded <- function(pkg, vers = NULL) {
  if (!require(pkg, character.only=TRUE, quietly =TRUE))
    BiocManager::install(pkgs=pkg, version=vers)
}

bcpkgs <- list(list(pkg="BiocManager",vers="3.10"),
               list(pkg="TxDb.Hsapiens.UCSC.hg38.knownGene",vers="3.10"),
               list(pkg="org.Hs.eg.db"),
               list(pkg="GO.db"),
               list(pkg="qvalue", vers="3.10")
               )

invisible(lapply(bcpkgs, function(x) 
    do.call(getBiocPackageIfNeeded, args=x)))
pkgs    <-  c("devtools","uwot","umap","Seurat")
invisible(sapply(pkgs,getPackageIfNeeded))
if (!require("NNLM")) 
  devtools::install_version("NNLM", version = "0.4.3")
if (!require("swne")) 
  devtools::install_github("yanwu2014/swne")
if (!require("perturbLM")) 
  devtools::install_github("yanwu2014/perturbLM", upgrade = "never")

Summary of steps to be run

Set the file.handle parameter to the name of the sample to be analyzed (this can include path information if data not in the same directory as this file). Generate a summary table for each sample, as well as cluster enrichment heatmaps, tSNE plots, and differential expression barplots.

The hESC_run_regression.R and hESC_run_clustering.R must have been run on the sample first. (This has already been done by Parekh et al.)

Step 1

Load all required libraries.

#### Create t-SNE plots, differential expression heatmaps, and cluster enrichment heatmaps
library(perturbLM)
library(swne)
library(ggplot2)
library(RColorBrewer)
library(Seurat)
library(grid)
library(gtable)

Step 2

Define file locations and load data. Example below includes path information for my computer. Must be modified to work appropriately on your computer.

## Name of the sample to be analyzed
file.handle <- "~/Downloads/Parekh_paper_data/up-tf-stem"
#file.handle <- "up-tf-stem"
# file.handle <- "up-tf-endo"
# file.handle <- "up-tf-multi"
# file.handle <- "up-tf-klf"
# file.handle <- "up-tf-myc"
# file.handle <- "up-tf-neuron-nohygro"

## Load regression results
coefs.df <- read.table(paste(file.handle, "regression.pvals.tsv", sep = "_"), sep = "\t", 
                       header = T, stringsAsFactors = F)
top.coefs.df <- subset(coefs.df, FDR < 0.05 & abs(cf) > 0.025)
print(sort(table(top.coefs.df$Group), decreasing = T))

            KLF4             CDX2            SNAI2          ONECUT1 
             487              272              226              132 
            MYOG            ASCL1          NEUROD1            MYOD1 
             122              121              112              101 
            TBX5              MYC            HNF1A            RUNX1 
              55               50               47               45 
         NEUROG3            ASCL4            MESP1          NEUROG1 
              44               39               36               35 
            LHX3            ASCL3             OTX2             SPI1 
              33               31               30               28 
          TFAP2C             SOX2             PAX7            FOXA3 
              27               23               22               20 
           ASCL5              CRX            HAND2            HOXA1 
              19               18               18               18 
            SPIC             SOX3            FOXA2            SOX10 
              17               16               15               15 
          HOXA11           POU1F1            GATA4             SIX2 
              14               13               12               11 
            ETV2            ESRRG            GATA2            HOXB6 
               9                6                6                5 
            SPIB            GATA1            MEF2C             MITF 
               4                3                3                3 
            SIX1              ERG           HOXA10            LMX1A 
               3                2                2                2 
mCherry-int-ctrl             MYCL              SRY             ATF7 
               2                2                2                1 
           FOXP1              NRL 
               1                1 
## Load clustering
r <- readRDS(paste(file.handle, "clustering.Robj", sep = "_"))


clusters <- r@ident; names(clusters) <- r@cell.names;
levels(clusters) <- paste("C", levels(clusters), sep = "")
clusters.list <- UnflattenGroups(clusters)

# update v2 Seurat object to v3
r <- UpdateSeuratObject(r)
Updating from v2.X to v3.X
Validating object structure
Updating object slots
Ensuring keys are in the proper strucutre
Ensuring feature names don't have underscores or pipes
Object representation is consistent with the most current Seurat version
## Load genotypes
# genotypes.list <- ReadGenotypes("up-tf-klf-myc_pheno_dict.csv")
genotypes.list <- ReadGenotypes(paste(file.handle, "pheno_dict.csv", sep = "_"))
genotypes.list <- lapply(genotypes.list, function(x) x[x %in% names(clusters)])
genotypes.sizes <- sapply(genotypes.list, length)

Step 3

Calculate enrichment scores and summarize results.

##  Calculate genotype enrichment
genotypes.cl.tbl <- GenotypeClusterCounts(genotypes.list, clusters.list)
genotypes.cl.pvals <- GenotypeClusterPvals(genotypes.cl.tbl)

genotypes.min.p <- apply(genotypes.cl.pvals, 1, function(x) min(abs(x)) * length(x))
metap::sumlog(genotypes.min.p)
Some studies omitted
chisq =  3750.279  with df =  118  p =  0 
## Summarize analysis results
genotype.counts <- sort(table(top.coefs.df$Group), decreasing = T)
genotype.counts <- genotype.counts[names(genotype.counts) %in% rownames(genotypes.cl.pvals)]
genotype.avg_cf <- tapply(top.coefs.df$cf, top.coefs.df$Group, function(x) mean(abs(x)))[names(genotype.counts)]

genotype.summary <- data.frame(n_diff_genes = as.integer(genotype.counts), avg_cf = genotype.avg_cf)
genotype.summary$min_cluster_pval <- apply(genotypes.cl.pvals[rownames(genotype.summary), ], 1, function(x) min(abs(x)))
genotype.summary$min_cluster <- apply(genotypes.cl.pvals[rownames(genotype.summary), ], 1, function(x) names(x[which.min(abs(x))]))
genotype.summary$n_cells <- genotypes.sizes[rownames(genotype.summary)]

Uncomment code below if you want to save the output data to a file.

# write.table(genotype.summary, file = paste(file.handle, "summary.tsv", sep = "_"), sep = "\t")

Step 4

Continue processing to identify significant genotypes.

## Determine significant genotypes
min.cl.pval <- 1e-12
min.diff.genes <- 40
ctrl.cl <- genotype.summary["mCherry", "min_cluster"]
sig.genotypes <- rownames(subset(genotype.summary, (abs(min_cluster_pval) < min.cl.pval & min_cluster != ctrl.cl) 
                                 | n_diff_genes > min.diff.genes))
sig.genotypes <- sort(unique(c(sig.genotypes, "mCherry-int-ctrl")), decreasing = T); print(sig.genotypes);
 [1] "TBX5"             "SNAI2"            "RUNX1"           
 [4] "ONECUT1"          "NEUROG3"          "NEUROG1"         
 [7] "NEUROD1"          "MYOG"             "MYOD1"           
[10] "MYC"              "mCherry-int-ctrl" "KLF4"            
[13] "HNF1A"            "CDX2"             "ASCL4"           
[16] "ASCL1"           

Step 5

Generate barplot graph.

## Differential expression barplot
n.diff.genes <- genotype.summary[sig.genotypes, "n_diff_genes"]
names(n.diff.genes) <- sig.genotypes
gg.bar <- ggBarplot(n.diff.genes, fill.color = "purple")

# pdf(paste(file.handle, "diff_genes_barplot.pdf", sep = "_"), width = 3.5, height = 1.5)
# print(gg.bar)
# dev.off()

## Cluster enrichment heatmap (Figure 1c-e)
max.lp <- 50

genotypes.cl.lp <- apply(genotypes.cl.pvals[sig.genotypes,], 1:2, function(x) ifelse(x > 0, -log10(x), log10(-1 * x)))
genotypes.cl.lp[genotypes.cl.lp > max.lp] <- max.lp
genotypes.cl.lp[genotypes.cl.lp < -1 * max.lp] <- -1 * max.lp

# pdf(paste(file.handle, "cl_enrich_heatmap.pdf", sep = "_"), width = 4.5, height = 5)
# ggHeat(genotypes.cl.lp, clustering = "none", x.lab.size = 14, y.lab.size = 14)
# dev.off()

gg.heat <- ggHeat(t(genotypes.cl.lp), clustering = "none", x.lab.size = 14, y.lab.size = 14)
gg.bar <- gg.bar + theme(axis.text.x = element_blank())
gg.heat <- gg.heat + theme(legend.position = "none")

gg.1 <- ggplotGrob(gg.heat)
gg.2 <- ggplotGrob(gg.bar)

gg.aligned <- rbind(gg.2, gg.1, size = "first")
gg.aligned$widths <- grid::unit.pmax(gg.1$widths, gg.2$widths)

#pdf(paste(file.handle, "stacked_diff_genes_cl_enrich_nolabels.pdf", sep = "_"), width = 5.5, height = 6)
grid::grid.newpage()

grid::grid.draw(gg.aligned)

#dev.off()

Step 6

Generate tSNE plots

## tSNE plots (Figure 1c-e)
plot.seed <- 32907098
tsne.emb <- Embeddings(object = r, reduction = "tsne")

#pdf(paste(file.handle, "tsne_plot.pdf", sep = "_"), width = 4, height = 4)
PlotDims(tsne.emb, sample.groups = clusters, pt.size = 0.75, alpha.plot = 0.5, label.size = 6, do.label = T,
         show.legend = F, seed = plot.seed)

#dev.off()

#pdf(paste(file.handle, "tsne_plot_nolabel.pdf", sep = "_"), width = 4, height = 4)
PlotDims(tsne.emb, sample.groups = clusters, pt.size = 0.75, alpha.plot = 0.5, label.size = 0, do.label = F,
         show.legend = F, seed = plot.seed)

#dev.off()

#pdf(paste(file.handle, "tsne_plot_batch.pdf", sep = "_"), width = 4, height = 4)
batch <- factor(r@meta.data$batch)
# names(batch) <- r@cell.names
names(batch) <- colnames(r)

batch <- batch[rownames(tsne.emb)]

PlotDims(tsne.emb, sample.groups = batch, pt.size = 1, alpha.plot = 0.5, label.size = 8, do.label = T,
         show.legend = F, seed = plot.seed)

#dev.off()


## tSNE plot overlay
# plot.seed <- 32907098
# tsne.emb <- Embeddings(object = r, reduction = "tsne")

TF <- "NEUROD1"

tf.groups <- as.character(clusters); names(tf.groups) <- names(clusters);
tf.groups[names(tf.groups) %in% genotypes.list[[TF]]] <- TF
tf.groups[!names(tf.groups) %in% genotypes.list[[TF]]] <- ""
tf.groups <- factor(tf.groups)

#pdf(paste0(file.handle, "_tsne_plot_", TF, ".pdf"), width = 3, height = 3)
PlotDims(tsne.emb, sample.groups = tf.groups, pt.size = 0.35, alpha.plot = 0.4, label.size = 0, do.label = T,
         show.legend = F, seed = plot.seed) + scale_color_manual(values = c("grey", "red")) + ggtitle(TF)

#dev.off()
LS0tCnRpdGxlOiAiUGFyZWtoIHBhcGVyIGZpZ3VyZXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgUm1kOiBkZWZhdWx0Ci0tLQoKIyMgQ29kZSB0byBwcm9jZXNzIFBhcmVraCBwYXBlciBkYXRhClRoaXMgY29kZSBpcyBhc3NlbWJsZWQgdG8gcGVyZm9ybSB0aGUgc3RlcHMgdG8gc3VtbWFyaXplIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhbmQgY2x1c3RlcnMgb2YgY2VsbHMuIFRoZSBwcm9jZXNzZWQgZGF0YSB3ZXJlIGRvd25sb2FkZWQgYW5kIHNhdmVkIGluIGBTRVVTU19wcm9jZXNzZWRfZGF0YWAuCgpUaGlzIGNhZGUgaGFzIGJlZW4gcHVsbGVkIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3lhbnd1MjAxNC9TRVVTUy1BbmFseXNpcyBhbmQgc3BlY2lmaWNhbGx5IGNvcGllZCBmcm9tIGBoRVNDX3N1bW1hcml6ZV9yZXN1bHRzLlJgCgpUaGUgZGF0YSBmb3IgY2VsbHMgY3VsdHVyZWQgaW4gdGhlIHBsdXJpcG90ZW50IHN0ZW0gY2VsbCBtZWRpdW0gaGFzIGJlZW4gcHV0IGludG8gYSBjb21wcmVzc2VkIGZpbGUgaW4gdGhlIEdvb2dsZSBEcml2ZS4gWW91IHNob3VsZCBiZSBhYmxlIHRvIGRvd25sb2FkIGl0IGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOiBodHRwczovL2RyaXZlLmdvb2dsZS5jb20vb3Blbj9pZD0xOXFIc1JGTzRRd0hob3R4dXc3M01ZUkhCOENGWVBNM2MgYW5kIGV4dHJhY3QgdGhlIGZpbGVzIG9udG8geW91ciBsb2NhbCBjb21wdXRlci4gWW91IHdpbGwgYWxzbyBuZWVkIHRvIGNoYW5nZSB0aGUgYGZpbGUuaGFuZGxlYCBhcHByb3ByaWF0ZWx5IChzZWUgYmVsb3cpLgoKIyMjIyBOT1RFClRoZSBmb2xsb3dpbmcgcGFja2FnZXMgbXVzdCBiZSBpbnN0YWxsZWQgcHJpb3IgdG8gcnVubmluZyAobWFueSBuZWVkZWQgb25seSB0byBsb2FkIGBzd25lYCBwYWNrYWdlLiBVbmNvbW1lbnQgdG8gZXhlY3V0ZS4KCmBgYHtyLCByZXN1bHRzPUZBTFNFfQpnZXRQYWNrYWdlSWZOZWVkZWQgPC0gZnVuY3Rpb24ocGtnKSB7CiAgaWYgKCFyZXF1aXJlKHBrZywgY2hhcmFjdGVyLm9ubHk9VFJVRSwgcXVpZXRseSA9VFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKHBrZ3M9cGtnLCBkZXBlbmRlbmNpZXM9VFJVRSkKfQpnZXRCaW9jUGFja2FnZUlmTmVlZGVkIDwtIGZ1bmN0aW9uKHBrZywgdmVycyA9IE5VTEwpIHsKICBpZiAoIXJlcXVpcmUocGtnLCBjaGFyYWN0ZXIub25seT1UUlVFLCBxdWlldGx5ID1UUlVFKSkKICAgIEJpb2NNYW5hZ2VyOjppbnN0YWxsKHBrZ3M9cGtnLCB2ZXJzaW9uPXZlcnMpCn0KCmJjcGtncyA8LSBsaXN0KGxpc3QocGtnPSJCaW9jTWFuYWdlciIsdmVycz0iMy4xMCIpLAogICAgICAgICAgICAgICBsaXN0KHBrZz0iVHhEYi5Ic2FwaWVucy5VQ1NDLmhnMzgua25vd25HZW5lIix2ZXJzPSIzLjEwIiksCiAgICAgICAgICAgICAgIGxpc3QocGtnPSJvcmcuSHMuZWcuZGIiKSwKICAgICAgICAgICAgICAgbGlzdChwa2c9IkdPLmRiIiksCiAgICAgICAgICAgICAgIGxpc3QocGtnPSJxdmFsdWUiLCB2ZXJzPSIzLjEwIikKICAgICAgICAgICAgICAgKQoKaW52aXNpYmxlKGxhcHBseShiY3BrZ3MsIGZ1bmN0aW9uKHgpIAogICAgZG8uY2FsbChnZXRCaW9jUGFja2FnZUlmTmVlZGVkLCBhcmdzPXgpKSkKCnBrZ3MJPC0JYygiZGV2dG9vbHMiLCJ1d290IiwidW1hcCIsIlNldXJhdCIpCmludmlzaWJsZShzYXBwbHkocGtncyxnZXRQYWNrYWdlSWZOZWVkZWQpKQppZiAoIXJlcXVpcmUoIk5OTE0iKSkgCiAgZGV2dG9vbHM6Omluc3RhbGxfdmVyc2lvbigiTk5MTSIsIHZlcnNpb24gPSAiMC40LjMiKQppZiAoIXJlcXVpcmUoInN3bmUiKSkgCiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ5YW53dTIwMTQvc3duZSIpCmlmICghcmVxdWlyZSgicGVydHVyYkxNIikpIAogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigieWFud3UyMDE0L3BlcnR1cmJMTSIsIHVwZ3JhZGUgPSAibmV2ZXIiKQpgYGAKCiMjIyMgU3VtbWFyeSBvZiBzdGVwcyB0byBiZSBydW4KU2V0IHRoZSBgZmlsZS5oYW5kbGVgIHBhcmFtZXRlciB0byB0aGUgbmFtZSBvZiB0aGUgc2FtcGxlIHRvIGJlIGFuYWx5emVkICh0aGlzIGNhbiBpbmNsdWRlIGBwYXRoYCBpbmZvcm1hdGlvbiBpZiBkYXRhIG5vdCBpbiB0aGUgc2FtZSBkaXJlY3RvcnkgYXMgdGhpcyBmaWxlKS4gR2VuZXJhdGUgYSBzdW1tYXJ5IHRhYmxlIGZvciBlYWNoIHNhbXBsZSwgYXMgd2VsbCBhcyBjbHVzdGVyIGVucmljaG1lbnQgaGVhdG1hcHMsIHRTTkUgcGxvdHMsIGFuZCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiYXJwbG90cy4gCgpUaGUgYGhFU0NfcnVuX3JlZ3Jlc3Npb24uUmAgYW5kIGBoRVNDX3J1bl9jbHVzdGVyaW5nLlJgIG11c3QgaGF2ZSBiZWVuIHJ1biBvbiB0aGUgc2FtcGxlIGZpcnN0LiAoVGhpcyBoYXMgYWxyZWFkeSBiZWVuIGRvbmUgYnkgUGFyZWtoIGV0IGFsLikKCiMjIyMgU3RlcCAxCkxvYWQgYWxsIHJlcXVpcmVkIGxpYnJhcmllcy4KYGBge3J9CiMjIyMgQ3JlYXRlIHQtU05FIHBsb3RzLCBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBoZWF0bWFwcywgYW5kIGNsdXN0ZXIgZW5yaWNobWVudCBoZWF0bWFwcwpsaWJyYXJ5KHBlcnR1cmJMTSkKbGlicmFyeShzd25lKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGd0YWJsZSkKCmBgYAogCiMjIyMgU3RlcCAyCkRlZmluZSBmaWxlIGxvY2F0aW9ucyBhbmQgbG9hZCBkYXRhLiBFeGFtcGxlIGJlbG93IGluY2x1ZGVzIHBhdGggaW5mb3JtYXRpb24gZm9yIG15IGNvbXB1dGVyLiBNdXN0IGJlIG1vZGlmaWVkIHRvIHdvcmsgYXBwcm9wcmlhdGVseSBvbiB5b3VyIGNvbXB1dGVyLgoKYGBge3J9CiMjIE5hbWUgb2YgdGhlIHNhbXBsZSB0byBiZSBhbmFseXplZApmaWxlLmhhbmRsZSA8LSAifi9Eb3dubG9hZHMvUGFyZWtoX3BhcGVyX2RhdGEvdXAtdGYtc3RlbSIKI2ZpbGUuaGFuZGxlIDwtICJ1cC10Zi1zdGVtIgojIGZpbGUuaGFuZGxlIDwtICJ1cC10Zi1lbmRvIgojIGZpbGUuaGFuZGxlIDwtICJ1cC10Zi1tdWx0aSIKIyBmaWxlLmhhbmRsZSA8LSAidXAtdGYta2xmIgojIGZpbGUuaGFuZGxlIDwtICJ1cC10Zi1teWMiCiMgZmlsZS5oYW5kbGUgPC0gInVwLXRmLW5ldXJvbi1ub2h5Z3JvIgoKIyMgTG9hZCByZWdyZXNzaW9uIHJlc3VsdHMKY29lZnMuZGYgPC0gcmVhZC50YWJsZShwYXN0ZShmaWxlLmhhbmRsZSwgInJlZ3Jlc3Npb24ucHZhbHMudHN2Iiwgc2VwID0gIl8iKSwgc2VwID0gIlx0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnRvcC5jb2Vmcy5kZiA8LSBzdWJzZXQoY29lZnMuZGYsIEZEUiA8IDAuMDUgJiBhYnMoY2YpID4gMC4wMjUpCnByaW50KHNvcnQodGFibGUodG9wLmNvZWZzLmRmJEdyb3VwKSwgZGVjcmVhc2luZyA9IFQpKQoKIyMgTG9hZCBjbHVzdGVyaW5nCnIgPC0gcmVhZFJEUyhwYXN0ZShmaWxlLmhhbmRsZSwgImNsdXN0ZXJpbmcuUm9iaiIsIHNlcCA9ICJfIikpCgoKY2x1c3RlcnMgPC0gckBpZGVudDsgbmFtZXMoY2x1c3RlcnMpIDwtIHJAY2VsbC5uYW1lczsKbGV2ZWxzKGNsdXN0ZXJzKSA8LSBwYXN0ZSgiQyIsIGxldmVscyhjbHVzdGVycyksIHNlcCA9ICIiKQpjbHVzdGVycy5saXN0IDwtIFVuZmxhdHRlbkdyb3VwcyhjbHVzdGVycykKCiMgdXBkYXRlIHYyIFNldXJhdCBvYmplY3QgdG8gdjMKciA8LSBVcGRhdGVTZXVyYXRPYmplY3QocikKCiMjIExvYWQgZ2Vub3R5cGVzCiMgZ2Vub3R5cGVzLmxpc3QgPC0gUmVhZEdlbm90eXBlcygidXAtdGYta2xmLW15Y19waGVub19kaWN0LmNzdiIpCmdlbm90eXBlcy5saXN0IDwtIFJlYWRHZW5vdHlwZXMocGFzdGUoZmlsZS5oYW5kbGUsICJwaGVub19kaWN0LmNzdiIsIHNlcCA9ICJfIikpCmdlbm90eXBlcy5saXN0IDwtIGxhcHBseShnZW5vdHlwZXMubGlzdCwgZnVuY3Rpb24oeCkgeFt4ICVpbiUgbmFtZXMoY2x1c3RlcnMpXSkKZ2Vub3R5cGVzLnNpemVzIDwtIHNhcHBseShnZW5vdHlwZXMubGlzdCwgbGVuZ3RoKQpgYGAKCiMjIyMgU3RlcCAzCkNhbGN1bGF0ZSBlbnJpY2htZW50IHNjb3JlcyBhbmQgc3VtbWFyaXplIHJlc3VsdHMuCmBgYHtyfQojIyAgQ2FsY3VsYXRlIGdlbm90eXBlIGVucmljaG1lbnQKZ2Vub3R5cGVzLmNsLnRibCA8LSBHZW5vdHlwZUNsdXN0ZXJDb3VudHMoZ2Vub3R5cGVzLmxpc3QsIGNsdXN0ZXJzLmxpc3QpCmdlbm90eXBlcy5jbC5wdmFscyA8LSBHZW5vdHlwZUNsdXN0ZXJQdmFscyhnZW5vdHlwZXMuY2wudGJsKQoKZ2Vub3R5cGVzLm1pbi5wIDwtIGFwcGx5KGdlbm90eXBlcy5jbC5wdmFscywgMSwgZnVuY3Rpb24oeCkgbWluKGFicyh4KSkgKiBsZW5ndGgoeCkpCm1ldGFwOjpzdW1sb2coZ2Vub3R5cGVzLm1pbi5wKQoKIyMgU3VtbWFyaXplIGFuYWx5c2lzIHJlc3VsdHMKZ2Vub3R5cGUuY291bnRzIDwtIHNvcnQodGFibGUodG9wLmNvZWZzLmRmJEdyb3VwKSwgZGVjcmVhc2luZyA9IFQpCmdlbm90eXBlLmNvdW50cyA8LSBnZW5vdHlwZS5jb3VudHNbbmFtZXMoZ2Vub3R5cGUuY291bnRzKSAlaW4lIHJvd25hbWVzKGdlbm90eXBlcy5jbC5wdmFscyldCmdlbm90eXBlLmF2Z19jZiA8LSB0YXBwbHkodG9wLmNvZWZzLmRmJGNmLCB0b3AuY29lZnMuZGYkR3JvdXAsIGZ1bmN0aW9uKHgpIG1lYW4oYWJzKHgpKSlbbmFtZXMoZ2Vub3R5cGUuY291bnRzKV0KCmdlbm90eXBlLnN1bW1hcnkgPC0gZGF0YS5mcmFtZShuX2RpZmZfZ2VuZXMgPSBhcy5pbnRlZ2VyKGdlbm90eXBlLmNvdW50cyksIGF2Z19jZiA9IGdlbm90eXBlLmF2Z19jZikKZ2Vub3R5cGUuc3VtbWFyeSRtaW5fY2x1c3Rlcl9wdmFsIDwtIGFwcGx5KGdlbm90eXBlcy5jbC5wdmFsc1tyb3duYW1lcyhnZW5vdHlwZS5zdW1tYXJ5KSwgXSwgMSwgZnVuY3Rpb24oeCkgbWluKGFicyh4KSkpCmdlbm90eXBlLnN1bW1hcnkkbWluX2NsdXN0ZXIgPC0gYXBwbHkoZ2Vub3R5cGVzLmNsLnB2YWxzW3Jvd25hbWVzKGdlbm90eXBlLnN1bW1hcnkpLCBdLCAxLCBmdW5jdGlvbih4KSBuYW1lcyh4W3doaWNoLm1pbihhYnMoeCkpXSkpCmdlbm90eXBlLnN1bW1hcnkkbl9jZWxscyA8LSBnZW5vdHlwZXMuc2l6ZXNbcm93bmFtZXMoZ2Vub3R5cGUuc3VtbWFyeSldCmBgYAoKVW5jb21tZW50IGNvZGUgYmVsb3cgaWYgeW91IHdhbnQgdG8gc2F2ZSB0aGUgb3V0cHV0IGRhdGEgdG8gYSBmaWxlLgpgYGB7cn0KIyB3cml0ZS50YWJsZShnZW5vdHlwZS5zdW1tYXJ5LCBmaWxlID0gcGFzdGUoZmlsZS5oYW5kbGUsICJzdW1tYXJ5LnRzdiIsIHNlcCA9ICJfIiksIHNlcCA9ICJcdCIpCmBgYAoKIyMjIyBTdGVwIDQKQ29udGludWUgcHJvY2Vzc2luZyB0byBpZGVudGlmeSBzaWduaWZpY2FudCBnZW5vdHlwZXMuCmBgYHtyfQojIyBEZXRlcm1pbmUgc2lnbmlmaWNhbnQgZ2Vub3R5cGVzCm1pbi5jbC5wdmFsIDwtIDFlLTEyCm1pbi5kaWZmLmdlbmVzIDwtIDQwCmN0cmwuY2wgPC0gZ2Vub3R5cGUuc3VtbWFyeVsibUNoZXJyeSIsICJtaW5fY2x1c3RlciJdCnNpZy5nZW5vdHlwZXMgPC0gcm93bmFtZXMoc3Vic2V0KGdlbm90eXBlLnN1bW1hcnksIChhYnMobWluX2NsdXN0ZXJfcHZhbCkgPCBtaW4uY2wucHZhbCAmIG1pbl9jbHVzdGVyICE9IGN0cmwuY2wpIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IG5fZGlmZl9nZW5lcyA+IG1pbi5kaWZmLmdlbmVzKSkKc2lnLmdlbm90eXBlcyA8LSBzb3J0KHVuaXF1ZShjKHNpZy5nZW5vdHlwZXMsICJtQ2hlcnJ5LWludC1jdHJsIikpLCBkZWNyZWFzaW5nID0gVCk7IHByaW50KHNpZy5nZW5vdHlwZXMpOwpgYGAKCiMjIyMgU3RlcCA1CkdlbmVyYXRlIGJhcnBsb3QgZ3JhcGguCmBgYHtyfQojIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBiYXJwbG90Cm4uZGlmZi5nZW5lcyA8LSBnZW5vdHlwZS5zdW1tYXJ5W3NpZy5nZW5vdHlwZXMsICJuX2RpZmZfZ2VuZXMiXQpuYW1lcyhuLmRpZmYuZ2VuZXMpIDwtIHNpZy5nZW5vdHlwZXMKZ2cuYmFyIDwtIGdnQmFycGxvdChuLmRpZmYuZ2VuZXMsIGZpbGwuY29sb3IgPSAicHVycGxlIikKCiMgcGRmKHBhc3RlKGZpbGUuaGFuZGxlLCAiZGlmZl9nZW5lc19iYXJwbG90LnBkZiIsIHNlcCA9ICJfIiksIHdpZHRoID0gMy41LCBoZWlnaHQgPSAxLjUpCiMgcHJpbnQoZ2cuYmFyKQojIGRldi5vZmYoKQoKIyMgQ2x1c3RlciBlbnJpY2htZW50IGhlYXRtYXAgKEZpZ3VyZSAxYy1lKQptYXgubHAgPC0gNTAKCmdlbm90eXBlcy5jbC5scCA8LSBhcHBseShnZW5vdHlwZXMuY2wucHZhbHNbc2lnLmdlbm90eXBlcyxdLCAxOjIsIGZ1bmN0aW9uKHgpIGlmZWxzZSh4ID4gMCwgLWxvZzEwKHgpLCBsb2cxMCgtMSAqIHgpKSkKZ2Vub3R5cGVzLmNsLmxwW2dlbm90eXBlcy5jbC5scCA+IG1heC5scF0gPC0gbWF4LmxwCmdlbm90eXBlcy5jbC5scFtnZW5vdHlwZXMuY2wubHAgPCAtMSAqIG1heC5scF0gPC0gLTEgKiBtYXgubHAKCiMgcGRmKHBhc3RlKGZpbGUuaGFuZGxlLCAiY2xfZW5yaWNoX2hlYXRtYXAucGRmIiwgc2VwID0gIl8iKSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDUpCiMgZ2dIZWF0KGdlbm90eXBlcy5jbC5scCwgY2x1c3RlcmluZyA9ICJub25lIiwgeC5sYWIuc2l6ZSA9IDE0LCB5LmxhYi5zaXplID0gMTQpCiMgZGV2Lm9mZigpCgpnZy5oZWF0IDwtIGdnSGVhdCh0KGdlbm90eXBlcy5jbC5scCksIGNsdXN0ZXJpbmcgPSAibm9uZSIsIHgubGFiLnNpemUgPSAxNCwgeS5sYWIuc2l6ZSA9IDE0KQpnZy5iYXIgPC0gZ2cuYmFyICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpCmdnLmhlYXQgPC0gZ2cuaGVhdCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmdnLjEgPC0gZ2dwbG90R3JvYihnZy5oZWF0KQpnZy4yIDwtIGdncGxvdEdyb2IoZ2cuYmFyKQoKZ2cuYWxpZ25lZCA8LSByYmluZChnZy4yLCBnZy4xLCBzaXplID0gImZpcnN0IikKZ2cuYWxpZ25lZCR3aWR0aHMgPC0gZ3JpZDo6dW5pdC5wbWF4KGdnLjEkd2lkdGhzLCBnZy4yJHdpZHRocykKCiNwZGYocGFzdGUoZmlsZS5oYW5kbGUsICJzdGFja2VkX2RpZmZfZ2VuZXNfY2xfZW5yaWNoX25vbGFiZWxzLnBkZiIsIHNlcCA9ICJfIiksIHdpZHRoID0gNS41LCBoZWlnaHQgPSA2KQpncmlkOjpncmlkLm5ld3BhZ2UoKQpncmlkOjpncmlkLmRyYXcoZ2cuYWxpZ25lZCkKI2Rldi5vZmYoKQoKYGBgCgojIyMjIFN0ZXAgNgpHZW5lcmF0ZSB0U05FIHBsb3RzCmBgYHtyfQojIyB0U05FIHBsb3RzIChGaWd1cmUgMWMtZSkKcGxvdC5zZWVkIDwtIDMyOTA3MDk4CnRzbmUuZW1iIDwtIEVtYmVkZGluZ3Mob2JqZWN0ID0gciwgcmVkdWN0aW9uID0gInRzbmUiKQoKI3BkZihwYXN0ZShmaWxlLmhhbmRsZSwgInRzbmVfcGxvdC5wZGYiLCBzZXAgPSAiXyIpLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpClBsb3REaW1zKHRzbmUuZW1iLCBzYW1wbGUuZ3JvdXBzID0gY2x1c3RlcnMsIHB0LnNpemUgPSAwLjc1LCBhbHBoYS5wbG90ID0gMC41LCBsYWJlbC5zaXplID0gNiwgZG8ubGFiZWwgPSBULAogICAgICAgICBzaG93LmxlZ2VuZCA9IEYsIHNlZWQgPSBwbG90LnNlZWQpCiNkZXYub2ZmKCkKCiNwZGYocGFzdGUoZmlsZS5oYW5kbGUsICJ0c25lX3Bsb3Rfbm9sYWJlbC5wZGYiLCBzZXAgPSAiXyIpLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpClBsb3REaW1zKHRzbmUuZW1iLCBzYW1wbGUuZ3JvdXBzID0gY2x1c3RlcnMsIHB0LnNpemUgPSAwLjc1LCBhbHBoYS5wbG90ID0gMC41LCBsYWJlbC5zaXplID0gMCwgZG8ubGFiZWwgPSBGLAogICAgICAgICBzaG93LmxlZ2VuZCA9IEYsIHNlZWQgPSBwbG90LnNlZWQpCiNkZXYub2ZmKCkKCiNwZGYocGFzdGUoZmlsZS5oYW5kbGUsICJ0c25lX3Bsb3RfYmF0Y2gucGRmIiwgc2VwID0gIl8iKSwgd2lkdGggPSA0LCBoZWlnaHQgPSA0KQpiYXRjaCA8LSBmYWN0b3IockBtZXRhLmRhdGEkYmF0Y2gpCiMgbmFtZXMoYmF0Y2gpIDwtIHJAY2VsbC5uYW1lcwpuYW1lcyhiYXRjaCkgPC0gY29sbmFtZXMocikKCmJhdGNoIDwtIGJhdGNoW3Jvd25hbWVzKHRzbmUuZW1iKV0KClBsb3REaW1zKHRzbmUuZW1iLCBzYW1wbGUuZ3JvdXBzID0gYmF0Y2gsIHB0LnNpemUgPSAxLCBhbHBoYS5wbG90ID0gMC41LCBsYWJlbC5zaXplID0gOCwgZG8ubGFiZWwgPSBULAogICAgICAgICBzaG93LmxlZ2VuZCA9IEYsIHNlZWQgPSBwbG90LnNlZWQpCiNkZXYub2ZmKCkKCgojIyB0U05FIHBsb3Qgb3ZlcmxheQojIHBsb3Quc2VlZCA8LSAzMjkwNzA5OAojIHRzbmUuZW1iIDwtIEVtYmVkZGluZ3Mob2JqZWN0ID0gciwgcmVkdWN0aW9uID0gInRzbmUiKQoKVEYgPC0gIk5FVVJPRDEiCgp0Zi5ncm91cHMgPC0gYXMuY2hhcmFjdGVyKGNsdXN0ZXJzKTsgbmFtZXModGYuZ3JvdXBzKSA8LSBuYW1lcyhjbHVzdGVycyk7CnRmLmdyb3Vwc1tuYW1lcyh0Zi5ncm91cHMpICVpbiUgZ2Vub3R5cGVzLmxpc3RbW1RGXV1dIDwtIFRGCnRmLmdyb3Vwc1shbmFtZXModGYuZ3JvdXBzKSAlaW4lIGdlbm90eXBlcy5saXN0W1tURl1dXSA8LSAiIgp0Zi5ncm91cHMgPC0gZmFjdG9yKHRmLmdyb3VwcykKCiNwZGYocGFzdGUwKGZpbGUuaGFuZGxlLCAiX3RzbmVfcGxvdF8iLCBURiwgIi5wZGYiKSwgd2lkdGggPSAzLCBoZWlnaHQgPSAzKQpQbG90RGltcyh0c25lLmVtYiwgc2FtcGxlLmdyb3VwcyA9IHRmLmdyb3VwcywgcHQuc2l6ZSA9IDAuMzUsIGFscGhhLnBsb3QgPSAwLjQsIGxhYmVsLnNpemUgPSAwLCBkby5sYWJlbCA9IFQsCiAgICAgICAgIHNob3cubGVnZW5kID0gRiwgc2VlZCA9IHBsb3Quc2VlZCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleSIsICJyZWQiKSkgKyBnZ3RpdGxlKFRGKQojZGV2Lm9mZigpCmBgYAoK